//
//  Network+Upload.m
//  YanXiuWang
//
//  Created by 慧趣小歪 on 16/12/14.
//  Copyright © 2016年 小分队. All rights reserved.
//

#import "Network+Upload.h"


@interface RequestUpload () {
    @package
    NSString *_localFilePath;
    
    NSMutableData *_formData;
    NSData * _lastData;
    NSString * _lastName;
    NSString * _lastFileName;
    NSString * _lastMimeType;
    NSProgress *_progress;
    NET_PROGRESS_BLOCK _progressBlock;
}

@property (nonatomic, readonly) NSString *boundary;

@end

@interface RequestUpload (FormData) <UploadFormData>

- (void)appendToFormData;

@end

@interface UploadDelegate : NSObject <NSURLSessionDataDelegate>

@end

@implementation UploadDelegate



@end

#pragma mark - Network Manager Upload
@implementation NetworkManager (Upload)

- (NSURLSession *)uploadSession {
    static UploadDelegate *delegate;
    static NSURLSession *session;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        delegate = [UploadDelegate new];
//        NSString *configurationIdentifier = @"NETWORK_UPLOAD_BACKGROUND_IDENTIFIER";
//        NSURLSessionConfiguration *configuration;
//#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1100)
//        configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:configurationIdentifier];
//#else
//        configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:configurationIdentifier];
//#endif
        session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:delegate delegateQueue:[NSOperationQueue new]];
    });
    return session;
}

- (RequestUpload *)upload:(UPLOAD_FILE)formDataBlock {
    RequestUpload *request = [RequestUpload new];
    formDataBlock(request);
    [request appendToFormData];
    return request;
}

+ (NSMutableURLRequest *)getURLRequestWithUploadTask:(RequestUpload *)task {
    
    NSURL *url = [NSURL URLWithString:[task valueForKey:@"URL"]];
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15];
    
    request.HTTPMethod = @"POST";
    
    request.HTTPBody = task->_formData; //[NSData dataWithContentsOfFile:task.localFilePath];

    // 如果有 HeaderField 则设置
    NSDictionary *dict = [task valueForKey:@"Headers"];
    [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
        [request setValue:[NSString stringWithFormat:@"%@", obj] forHTTPHeaderField:key];
    }];
    
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", task.boundary]
   forHTTPHeaderField:@"Content-Type"];
    [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)task->_formData.length]
   forHTTPHeaderField:@"Content-Length"];
    return request;
}


@end


#pragma mark - Request Upload

@implementation RequestUpload (FormData)

- (void)appendToFormData {
    if (_lastData == nil) return;
    if (_formData == nil) _formData = [NSMutableData data];
    NSData *data;
    
    data = [[NSString stringWithFormat:@"--%@\r\n", self.boundary] dataUsingEncoding:NSUTF8StringEncoding];
    [_formData appendData:data];
    
    if (_lastName && _lastFileName) {
        data = [[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", _lastName, _lastFileName] dataUsingEncoding:NSUTF8StringEncoding];
    } else if (_lastName) {
        data = [[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", _lastName] dataUsingEncoding:NSUTF8StringEncoding];
    } else {
        data = [@"Content-Disposition: form-data\r\n" dataUsingEncoding:NSUTF8StringEncoding];
    }
    [_formData appendData:data];
    
    data = nil;
    if (_lastMimeType) {
        data = [[NSString stringWithFormat:@"Content-Type: %@\r\n", _lastMimeType] dataUsingEncoding:NSUTF8StringEncoding];
    } else if (_lastFileName) {
        data = [[NSString stringWithFormat:@"Content-Type: %@\r\n", @"application/octet-stream"] dataUsingEncoding:NSUTF8StringEncoding];
    }
    if (data) [_formData appendData:data];
    
    data = [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding];
    [_formData appendData:data];        // 正文前另起一行
    [_formData appendData:_lastData];
    [_formData appendData:data];        // 结束另起一行
    
    // 结束后设空
    _lastMimeType = nil;
    _lastFileName = nil;
    _lastName = nil;
    _lastData = nil;
}

- (UPLOAD_FORM_DATA)data {
    [self appendToFormData];
    return ^(NSData * data) {
        _lastData = data;
        return self;
    };
}

- (UPLOAD_FORM_TEXT)path {
    return ^(NSString *path) {
        return self.data([NSData dataWithContentsOfFile:path]);
    };
}

- (UPLOAD_FORM_TEXT)name {
    return ^(NSString * value) {
        _lastName = value;
        return self;
    };
}

- (UPLOAD_FORM_TEXT)fileName {
    return ^(NSString * value) {
        _lastFileName = value;
        return self;
    };
}

- (UPLOAD_FORM_TEXT)mimeType {
    return ^(NSString * value) {
        _lastMimeType = value;
        return self;
    };
}

@end

@implementation RequestUpload


- (NSString *)boundary {
    static dispatch_once_t onceToken;
    static NSString *__boundary;
    dispatch_once(&onceToken, ^{
        __boundary = [NSString stringWithFormat:@"Boundary+%08X%08X", arc4random(), arc4random()];
    });
    return __boundary;
}

- (NET_POST)post {
    return ^(NSDictionary * params) {
        [params enumerateKeysAndObjectsUsingBlock:^(NSString * key, id obj, BOOL * stop) {
            NSString *value = [NSString stringWithFormat:@"%@", obj];
            self.data([value dataUsingEncoding:NSUTF8StringEncoding]).name(key);
        }];
        [self appendToFormData];
        return self;
    };
}

- (UPLOAD_TEXT)to {
    return ^(NSString *url) {
        [self setValue:url forKey:@"URL"];
        return self;
    };
}

- (NET_PROGRESS)progress {
    return ^(NET_PROGRESS_BLOCK progressBlock) {
        _progressBlock = [progressBlock copy];
        return self;
    };
}

- (NSURLSessionTask *)commit:(OnComplete)completeBlock {
    __block OnComplete onComplete = [completeBlock copy];
    __block NSMutableDictionary *source = [NSMutableDictionary dictionary];
    
    // 加入结束标记
    NSString *finalString = [NSString stringWithFormat:@"--%@--\r\n", self.boundary];
    [_formData appendData:[finalString dataUsingEncoding:NSUTF8StringEncoding]];
    
    NSURLRequest *request = [[NetworkManager getURLRequestWithUploadTask:self] copy];
    NSURLSession *session = [NetworkManager shared].uploadSession; /////[NSURLSession sharedSession];
    
    source[@"request"] = self;
    source[@"urlRequest"] = request;
    // 通知栏显示网络状态
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    
    _progress = [NSProgress progressWithTotalUnitCount:_formData.length];
    
    NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromData:_formData completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        // 通知栏关闭网络状态
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        
        source[@"task"] = task;
        source[@"data"] = data;
        source[@"error"] = error;
        
        if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
            NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
            source[@"state"] = @(httpResponse.statusCode);
            
            NSString *dateString = httpResponse.allHeaderFields[@"Date"] ?: @"Thu, 01 Jan 1970 00:00:00 GMT";
            NSDateFormatter *formatter = [NSDateFormatter new];
            formatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
            formatter.dateFormat = @"EEE, dd MMM yyyy HH:mm:ss Z";
            
            NSDate *date = [formatter dateFromString:dateString] ?: [NSDate dateWithTimeIntervalSince1970:0];
            [NetworkManager shared].timeOffset = date.timeIntervalSince1970 - [NSDate date].timeIntervalSince1970;
            source[@"date"] = date;
        }
        
        dispatch_async(dispatch_get_main_queue(), ^{
            ResponseNormal *response = [ResponseNormal new];
            response.source = source;
            onComplete(response);
        });
        
        // 移除进度监听
//        [task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))];
//        [task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))];
//        [_progress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
    }];
    
    // 添加进度监听
//    [_progress addObserver:self
//                forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
//                   options:NSKeyValueObservingOptionNew
//                   context:NULL];
//    
//    [task addObserver:self
//           forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))
//              options:NSKeyValueObservingOptionNew
//              context:NULL];
//    [task addObserver:self
//           forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))
//              options:NSKeyValueObservingOptionNew
//              context:NULL];
    
    [task resume];
    return task;
}
//
//- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
//    if ([object isEqual:_progress]) {
//        if (_progressBlock) _progressBlock(object);
//    } else if ([object isKindOfClass:[NSURLSessionTask class]] ||
//               [object isKindOfClass:[NSURLSessionUploadTask class]]) {
//        if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
//            _progress.completedUnitCount = [change[@"new"] longLongValue];
//        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]) {
//            _progress.totalUnitCount = [change[@"new"] longLongValue];
//        }
//    }
//}

@end
